//! ARIA属性支持模块
//!
//! 本模块提供了WAI-ARIA属性的解析和验证功能，以支持无障碍性特性

use crate::{DomNode, HtmlParser, HtmlParserError, NodeType};
use once_cell::sync::Lazy;
use std::collections::{HashMap, HashSet};

/// ARIA角色类型
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum AriaRoleCategory {
    /// 抽象角色 - 不应直接使用，而是作为其他角色的基础
    Abstract,
    /// 小部件角色 - 独立的用户界面小部件
    Widget,
    /// 复合小部件角色 - 由多个小部件组成的界面组件
    Composite,
    /// 文档结构角色 - 文档内容或文本的组织结构
    Structure,
    /// 地标角色 - 页面的主要部分
    Landmark,
    /// 窗口角色 - 浏览器或应用程序窗口
    Window,
    /// 实时区域角色 - 会自动更新的内容
    Live,
    /// 未知类别角色
    Unknown,
}

/// ARIA角色信息
#[derive(Debug, Clone)]
pub struct AriaRole {
    /// 角色名称
    pub name: String,
    /// 角色类别
    pub category: AriaRoleCategory,
    /// 是否已废弃
    pub deprecated: bool,
    /// 必需的子角色
    pub required_owned_elements: HashSet<String>,
    /// 必需的父角色
    pub required_context_role: HashSet<String>,
    /// 必需的ARIA属性
    pub required_attributes: HashSet<String>,
    /// 支持的ARIA属性
    pub supported_attributes: HashSet<String>,
    /// 是否可聚焦
    pub focusable: bool,
    /// 隐式角色（HTML元素默认对应的ARIA角色）
    pub implicit_for: HashSet<String>,
}

/// ARIA属性类型
#[derive(Debug, Clone, PartialEq)]
pub enum AriaAttributeType {
    /// 布尔值属性
    Boolean,
    /// 枚举值属性
    Enumerated(Vec<String>),
    /// 整数值属性
    Integer,
    /// 数字值属性
    Number,
    /// 字符串值属性
    String,
    /// 标识符引用属性（引用页面中其他元素的ID）
    IdRef,
    /// 多个标识符引用
    IdRefList,
    /// 通用的令牌属性
    Token,
    /// 令牌列表
    TokenList,
    /// 特殊定义的类型
    DefinedType(String),
}

/// ARIA属性信息
#[derive(Debug, Clone)]
pub struct AriaAttribute {
    /// 属性名称
    pub name: String,
    /// 属性类型
    pub value_type: AriaAttributeType,
    /// 默认值
    pub default_value: Option<String>,
    /// 是否已废弃
    pub deprecated: bool,
    /// 适用的角色（空表示全部适用）
    pub applicable_roles: HashSet<String>,
    /// 不适用的角色
    pub excluded_roles: HashSet<String>,
    /// 属性是否全局（适用于所有元素）
    pub global: bool,
    /// 属性描述
    pub description: String,
}

/// ARIA状态和属性管理器
#[derive(Debug)]
pub struct AriaManager {
    /// 所有ARIA角色
    roles: HashMap<String, AriaRole>,
    /// 所有ARIA属性
    attributes: HashMap<String, AriaAttribute>,
}

// 全局ARIA属性列表
static GLOBAL_ARIA_ATTRIBUTES: Lazy<HashSet<&'static str>> = Lazy::new(|| {
    let mut attrs = HashSet::new();
    // 状态属性
    attrs.insert("aria-busy");
    attrs.insert("aria-disabled");
    attrs.insert("aria-grabbed");
    attrs.insert("aria-hidden");
    attrs.insert("aria-invalid");

    // 属性
    attrs.insert("aria-atomic");
    attrs.insert("aria-controls");
    attrs.insert("aria-describedby");
    attrs.insert("aria-dropeffect");
    attrs.insert("aria-flowto");
    attrs.insert("aria-haspopup");
    attrs.insert("aria-label");
    attrs.insert("aria-labelledby");
    attrs.insert("aria-live");
    attrs.insert("aria-owns");
    attrs.insert("aria-relevant");
    attrs.insert("aria-roledescription");

    attrs
});

// ARIA属性和对应的类型映射表
static ARIA_ATTRIBUTE_TYPES: Lazy<HashMap<&'static str, AriaAttributeType>> = Lazy::new(|| {
    let mut types = HashMap::new();

    // 布尔属性
    let boolean_attrs = [
        "aria-busy",
        "aria-disabled",
        "aria-expanded",
        "aria-grabbed",
        "aria-hidden",
        "aria-modal",
        "aria-multiline",
        "aria-multiselectable",
        "aria-pressed",
        "aria-readonly",
        "aria-required",
        "aria-selected",
    ];
    for attr in boolean_attrs.iter() {
        types.insert(*attr, AriaAttributeType::Boolean);
    }

    // 枚举属性
    types.insert(
        "aria-autocomplete",
        AriaAttributeType::Enumerated(vec![
            "inline".to_string(),
            "list".to_string(),
            "both".to_string(),
            "none".to_string(),
        ]),
    );
    types.insert(
        "aria-current",
        AriaAttributeType::Enumerated(vec![
            "page".to_string(),
            "step".to_string(),
            "location".to_string(),
            "date".to_string(),
            "time".to_string(),
            "true".to_string(),
            "false".to_string(),
        ]),
    );
    types.insert(
        "aria-dropeffect",
        AriaAttributeType::Enumerated(vec![
            "copy".to_string(),
            "execute".to_string(),
            "link".to_string(),
            "move".to_string(),
            "none".to_string(),
            "popup".to_string(),
        ]),
    );
    types.insert(
        "aria-haspopup",
        AriaAttributeType::Enumerated(vec![
            "true".to_string(),
            "false".to_string(),
            "menu".to_string(),
            "listbox".to_string(),
            "tree".to_string(),
            "grid".to_string(),
            "dialog".to_string(),
        ]),
    );
    types.insert(
        "aria-invalid",
        AriaAttributeType::Enumerated(vec![
            "grammar".to_string(),
            "false".to_string(),
            "spelling".to_string(),
            "true".to_string(),
        ]),
    );
    types.insert(
        "aria-live",
        AriaAttributeType::Enumerated(vec![
            "assertive".to_string(),
            "off".to_string(),
            "polite".to_string(),
        ]),
    );
    types.insert(
        "aria-orientation",
        AriaAttributeType::Enumerated(vec![
            "horizontal".to_string(),
            "undefined".to_string(),
            "vertical".to_string(),
        ]),
    );
    types.insert("aria-relevant", AriaAttributeType::TokenList);
    types.insert(
        "aria-sort",
        AriaAttributeType::Enumerated(vec![
            "ascending".to_string(),
            "descending".to_string(),
            "none".to_string(),
            "other".to_string(),
        ]),
    );

    // ID引用属性
    let idref_attrs = ["aria-activedescendant", "aria-details", "aria-errormessage"];
    for attr in idref_attrs.iter() {
        types.insert(*attr, AriaAttributeType::IdRef);
    }

    // ID引用列表属性
    let idref_list_attrs = [
        "aria-controls",
        "aria-describedby",
        "aria-flowto",
        "aria-labelledby",
        "aria-owns",
    ];
    for attr in idref_list_attrs.iter() {
        types.insert(*attr, AriaAttributeType::IdRefList);
    }

    // 整数属性
    let integer_attrs = [
        "aria-colcount",
        "aria-colindex",
        "aria-colspan",
        "aria-level",
        "aria-posinset",
        "aria-rowcount",
        "aria-rowindex",
        "aria-rowspan",
        "aria-setsize",
    ];
    for attr in integer_attrs.iter() {
        types.insert(*attr, AriaAttributeType::Integer);
    }

    // 数字属性
    types.insert("aria-valuemax", AriaAttributeType::Number);
    types.insert("aria-valuemin", AriaAttributeType::Number);
    types.insert("aria-valuenow", AriaAttributeType::Number);

    // 字符串属性
    let string_attrs = [
        "aria-keyshortcuts",
        "aria-label",
        "aria-placeholder",
        "aria-roledescription",
        "aria-valuetext",
    ];
    for attr in string_attrs.iter() {
        types.insert(*attr, AriaAttributeType::String);
    }

    types
});

// HTML元素到隐式ARIA角色的映射
static HTML_TO_ARIA_ROLES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
    let mut mapping = HashMap::new();
    mapping.insert("a", "link"); // 有href属性时
    mapping.insert("article", "article");
    mapping.insert("aside", "complementary");
    mapping.insert("button", "button");
    mapping.insert("dialog", "dialog");
    mapping.insert("footer", "contentinfo");
    mapping.insert("form", "form");
    mapping.insert("h1", "heading");
    mapping.insert("h2", "heading");
    mapping.insert("h3", "heading");
    mapping.insert("h4", "heading");
    mapping.insert("h5", "heading");
    mapping.insert("h6", "heading");
    mapping.insert("header", "banner");
    mapping.insert("hr", "separator");
    mapping.insert("img", "img"); // 有alt属性时
    mapping.insert("input", "textbox"); // type=text时
    mapping.insert("input[type=button]", "button");
    mapping.insert("input[type=checkbox]", "checkbox");
    mapping.insert("input[type=radio]", "radio");
    mapping.insert("input[type=range]", "slider");
    mapping.insert("input[type=search]", "searchbox");
    mapping.insert("li", "listitem");
    mapping.insert("main", "main");
    mapping.insert("math", "math");
    mapping.insert("menu", "menu");
    mapping.insert("nav", "navigation");
    mapping.insert("ol", "list");
    mapping.insert("option", "option");
    mapping.insert("progress", "progressbar");
    mapping.insert("section", "region");
    mapping.insert("select", "listbox");
    mapping.insert("summary", "button");
    mapping.insert("table", "table");
    mapping.insert("tbody", "rowgroup");
    mapping.insert("textarea", "textbox");
    mapping.insert("thead", "rowgroup");
    mapping.insert("tr", "row");
    mapping.insert("ul", "list");

    mapping
});

impl AriaManager {
    /// 创建新的ARIA管理器
    pub fn new() -> Self {
        Self {
            roles: Self::initialize_roles(),
            attributes: Self::initialize_attributes(),
        }
    }

    /// 初始化ARIA角色
    fn initialize_roles() -> HashMap<String, AriaRole> {
        let mut roles = HashMap::new();

        // 这里仅实现几个常见角色作为示例
        // 实际实现中应包含更完整的角色列表

        // 按钮角色
        let mut button_role = AriaRole {
            name: "button".to_string(),
            category: AriaRoleCategory::Widget,
            deprecated: false,
            required_owned_elements: HashSet::new(),
            required_context_role: HashSet::new(),
            required_attributes: HashSet::new(),
            supported_attributes: HashSet::new(),
            focusable: true,
            implicit_for: HashSet::new(),
        };
        button_role.implicit_for.insert("button".to_string());
        button_role
            .implicit_for
            .insert("input[type=button]".to_string());
        button_role
            .implicit_for
            .insert("input[type=submit]".to_string());
        button_role
            .implicit_for
            .insert("input[type=reset]".to_string());
        button_role
            .supported_attributes
            .insert("aria-pressed".to_string());
        button_role
            .supported_attributes
            .insert("aria-expanded".to_string());
        roles.insert("button".to_string(), button_role);

        // 链接角色
        let mut link_role = AriaRole {
            name: "link".to_string(),
            category: AriaRoleCategory::Widget,
            deprecated: false,
            required_owned_elements: HashSet::new(),
            required_context_role: HashSet::new(),
            required_attributes: HashSet::new(),
            supported_attributes: HashSet::new(),
            focusable: true,
            implicit_for: HashSet::new(),
        };
        link_role.implicit_for.insert("a[href]".to_string());
        link_role
            .supported_attributes
            .insert("aria-expanded".to_string());
        roles.insert("link".to_string(), link_role);

        // 更多角色可以在这里添加...

        roles
    }

    /// 初始化ARIA属性
    fn initialize_attributes() -> HashMap<String, AriaAttribute> {
        let mut attributes = HashMap::new();

        // 这里实现几个常见属性作为示例
        // 完整实现应包含更多属性

        // aria-label属性
        let aria_label = AriaAttribute {
            name: "aria-label".to_string(),
            value_type: AriaAttributeType::String,
            default_value: None,
            deprecated: false,
            applicable_roles: HashSet::new(), // 空集表示适用于所有角色
            excluded_roles: HashSet::new(),
            global: true,
            description: "为元素提供可访问的名称".to_string(),
        };
        attributes.insert("aria-label".to_string(), aria_label);

        // aria-expanded属性
        let aria_expanded = AriaAttribute {
            name: "aria-expanded".to_string(),
            value_type: AriaAttributeType::Boolean,
            default_value: Some("false".to_string()),
            deprecated: false,
            applicable_roles: HashSet::new(),
            excluded_roles: HashSet::new(),
            global: false,
            description: "表示元素是否展开或折叠".to_string(),
        };
        attributes.insert("aria-expanded".to_string(), aria_expanded);

        // 更多属性可以在这里添加...

        attributes
    }

    /// 验证ARIA属性
    pub fn validate_aria_attribute(
        &self,
        attr_name: &str,
        attr_value: &str,
        element_role: Option<&str>,
    ) -> bool {
        // 检查属性是否存在
        if !attr_name.starts_with("aria-") && attr_name != "role" {
            return true; // 不是ARIA属性，不需要验证
        }

        if attr_name == "role" {
            // 验证角色值
            return self.roles.contains_key(attr_value)
                || attr_value == "presentation"
                || attr_value == "none";
        }

        // 处理全局属性
        if GLOBAL_ARIA_ATTRIBUTES.contains(attr_name) {
            // 如果是全局属性，检查值类型是否合法
            if let Some(attr_type) = ARIA_ATTRIBUTE_TYPES.get(attr_name) {
                return self.validate_attribute_value(attr_value, attr_type);
            }
            return true; // 全局属性，但没有明确的类型定义，暂时接受
        }

        // 查找属性定义
        if let Some(attr_def) = self.attributes.get(attr_name) {
            // 如果属性被废弃，发出警告但仍然通过验证
            if attr_def.deprecated {
                // 在实际应用中可以通过日志记录警告
                return true;
            }

            // 如果指定了适用的角色，检查当前元素的角色是否适用
            if !attr_def.applicable_roles.is_empty() && element_role.is_some() {
                if !attr_def.applicable_roles.contains(element_role.unwrap()) {
                    return false;
                }
            }

            // 如果指定了排除的角色，检查当前元素的角色是否被排除
            if !attr_def.excluded_roles.is_empty() && element_role.is_some() {
                if attr_def.excluded_roles.contains(element_role.unwrap()) {
                    return false;
                }
            }

            // 验证属性值类型
            return self.validate_attribute_value(attr_value, &attr_def.value_type);
        }

        // 对于未明确定义但以aria-开头的属性，尝试从ARIA_ATTRIBUTE_TYPES获取类型
        if let Some(attr_type) = ARIA_ATTRIBUTE_TYPES.get(attr_name) {
            return self.validate_attribute_value(attr_value, attr_type);
        }

        // 未知的ARIA属性，返回false
        false
    }

    /// 验证属性值是否符合类型要求
    pub fn validate_attribute_value(&self, value: &str, attr_type: &AriaAttributeType) -> bool {
        match attr_type {
            AriaAttributeType::Boolean => value == "true" || value == "false",
            AriaAttributeType::Enumerated(allowed_values) => {
                allowed_values.iter().any(|allowed| allowed == value)
            }
            AriaAttributeType::Integer => value.parse::<i32>().is_ok(),
            AriaAttributeType::Number => value.parse::<f64>().is_ok(),
            AriaAttributeType::String => {
                true // 任何字符串都是有效的
            }
            AriaAttributeType::IdRef => !value.is_empty() && !value.contains(char::is_whitespace),
            AriaAttributeType::IdRefList => value.split_whitespace().all(|id| !id.is_empty()),
            AriaAttributeType::Token => !value.is_empty() && !value.contains(char::is_whitespace),
            AriaAttributeType::TokenList => value.split_whitespace().all(|token| !token.is_empty()),
            AriaAttributeType::DefinedType(_) => {
                true // 特定类型的验证需要更复杂的实现
            }
        }
    }

    /// 获取元素的隐式ARIA角色
    pub fn get_implicit_role(&self, node: &DomNode) -> Option<&str> {
        if let NodeType::Element(tag_name) = &node.node_type {
            let tag = tag_name.as_ref();

            // 特殊处理带有属性的元素
            if tag == "a" {
                if node.get_attribute("href").is_some() {
                    return HTML_TO_ARIA_ROLES.get("a").copied();
                }
                return None;
            }

            if tag == "img" {
                if node.get_attribute("alt").is_some() {
                    return HTML_TO_ARIA_ROLES.get("img").copied();
                }
                return None;
            }

            if tag == "input" {
                if let Some(input_type) = node.get_attribute("type") {
                    let lookup_key = format!("input[type={}]", input_type);
                    if let Some(&role) = HTML_TO_ARIA_ROLES.get(lookup_key.as_str()) {
                        return Some(role);
                    }
                }
                return HTML_TO_ARIA_ROLES.get("input").copied();
            }

            // 查找常规映射
            HTML_TO_ARIA_ROLES.get(tag).copied()
        } else {
            None
        }
    }

    /// 检查元素是否有效地使用了ARIA
    pub fn check_valid_aria_usage(&self, node: &DomNode) -> Vec<String> {
        let mut issues = Vec::new();

        // 只检查元素节点
        if let NodeType::Element(_) = &node.node_type {
            // 获取显式角色
            let explicit_role = node.get_attribute("role");

            // 检查角色是否有效
            if let Some(role) = explicit_role {
                if !self.roles.contains_key(role) && role != "presentation" && role != "none" {
                    issues.push(format!("无效的ARIA角色: '{}'", role));
                }
            }

            // 获取元素的有效角色（显式或隐式）
            let effective_role = explicit_role.or_else(|| self.get_implicit_role(node));

            // 检查所有ARIA属性
            for attr in &node.attributes {
                if attr.name.starts_with("aria-") {
                    if !self.validate_aria_attribute(&attr.name, &attr.value, effective_role) {
                        issues.push(format!(
                            "无效的ARIA属性: '{}=\"{}\"'对于角色'{:?}'",
                            attr.name, attr.value, effective_role
                        ));
                    }
                }
            }

            // 检查必需的ARIA属性
            if let Some(role_name) = effective_role {
                if let Some(role) = self.roles.get(role_name) {
                    for required_attr in &role.required_attributes {
                        if !node
                            .attributes
                            .iter()
                            .any(|attr| &attr.name == required_attr)
                        {
                            issues.push(format!(
                                "缺少角色'{}'所需的ARIA属性: '{}'",
                                role_name, required_attr
                            ));
                        }
                    }
                }
            }
        }

        issues
    }
}

// 默认实现
impl Default for AriaManager {
    fn default() -> Self {
        Self::new()
    }
}

/// 扩展DomNode，增加ARIA相关方法
impl DomNode {
    /// 获取元素的ARIA角色
    pub fn get_aria_role(&self) -> Option<String> {
        // 首先检查显式角色
        if let Some(role) = self.get_attribute("role") {
            return Some(role.to_string());
        }

        // 然后检查隐式角色
        let aria_manager = AriaManager::new();
        aria_manager.get_implicit_role(self).map(|s| s.to_string())
    }

    /// 检查元素是否具有特定的ARIA属性
    pub fn has_aria_attribute(&self, name: &str) -> bool {
        self.get_attribute(name).is_some()
    }

    /// 检查元素是否可访问（非隐藏）
    pub fn is_accessible(&self) -> bool {
        // 检查aria-hidden属性
        if let Some(hidden) = self.get_attribute("aria-hidden") {
            return hidden != "true";
        }

        // 检查CSS隐藏（理想情况下应检查计算后的样式，但这里简化处理）
        if let Some(style) = self.get_attribute("style") {
            if style.contains("display: none") || style.contains("visibility: hidden") {
                return false;
            }
        }

        // 默认为可访问
        true
    }

    /// 获取元素的可访问名称
    pub fn get_accessible_name(&self) -> String {
        // 按照计算可访问名称的算法（简化版）：
        // 1. aria-labelledby (引用其他元素)
        // 2. aria-label
        // 3. 标签元素 (对表单控件)
        // 4. 标题属性
        // 5. 元素内容

        // 这里只实现简化版本
        if let Some(label) = self.get_attribute("aria-label") {
            return label.to_string();
        }

        if let Some(title) = self.get_attribute("title") {
            return title.to_string();
        }

        // 对于某些元素，使用其文本内容
        match &self.node_type {
            NodeType::Element(tag)
                if ["button", "a", "h1", "h2", "h3", "h4", "h5", "h6"].contains(&tag.as_ref()) =>
            {
                self.text_content()
            }
            NodeType::Element(tag) if tag.as_ref() == "img" => {
                self.get_attribute("alt").unwrap_or("").to_string()
            }
            _ => "".to_string(),
        }
    }
}

impl HtmlParser {
    /// 检查文档的ARIA可访问性
    pub fn check_accessibility(&self, dom: &DomNode) -> Vec<String> {
        let mut issues = Vec::new();
        let aria_manager = AriaManager::new();

        // 递归检查每个节点
        let mut check_node = |node: &DomNode| {
            // 检查ARIA使用
            let node_issues = aria_manager.check_valid_aria_usage(node);
            issues.extend(node_issues);

            // 其他可访问性检查可以在这里添加
            // 例如: 图片是否有alt文本
            if let NodeType::Element(tag) = &node.node_type {
                if tag.as_ref() == "img" && node.get_attribute("alt").is_none() {
                    issues.push("图片缺少alt属性，影响屏幕阅读器用户".to_string());
                }
            }
        };

        self.traverse(dom, &mut check_node);
        issues
    }
}
